//scroll-content为滚动区域， operation-btn为控制锚点行为的按钮。
<template>
    <div class="anchor-point">
        <!-- 滚动区域 -->
        <div class="scroll-content" @scroll="onScroll">
            <div class="scroll-item" style="height: 500px;background: #3a8ee6;">
                <div class="name">一层</div>
            </div>
            <div class="scroll-item" style="height: 500px;background: red;">
                <div class="name">二层</div>
            </div>
            <div class="scroll-item" style="height: 500px;background: #42b983">
                <div class="name">三层</div>
            </div>
            <div class="scroll-item" style="height: 1000px;background: yellow;">
                <div class="name">四层</div>
            </div>
        </div>
        <!-- 按钮 -->
        <div class="operation-btn">
            <div v-for="(item, index) in ['一层','二层','三层','四层']" :key="index" @click="jump(index)"
                :style="{background: activeStep === index ? '#eeeeee' : '#ffffff'}">{{item}}
            </div>
        </div>
    </div>
</template>
<script>
export default {
    data () {
        return {
            activeStep: 0
        }
    },
    methods: {
        // 通过监听滚动事件，高亮显示锚点按钮
        // 这里是通过遍历滚动项，判断滚动条滚动距离是否大于当前项的可滚动距离(即距离其offsetParent顶部的距离，这里是body)
        onScroll (e) {
            let scrollItems = document.querySelectorAll('.scroll-item')
            for (let i = scrollItems.length - 1; i >= 0; i--) {
                // 判断滚动条滚动距离是否大于当前滚动项可滚动距离
                let judge = e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop
                if (judge) {
                    this.activeStep = i
                    break
                }
            }
        },
        // 添加点击事件，根据锚点滚动至对应区域并实现平滑滚动
        // 这里参考网上的方法，将滚动距离细分为多个小段，并考虑向上及向下的的滚动，实现滚动的过渡动画。本来是打算使用scrollIntoView实现滚动动画，scrollIntoView在各个浏览器已经有很好的支持性，但是ScrollIntoViewOptions在浏览器的兼容性上还有问题，所以改用如下距离分割的方式。
        jump (index) {
            let target = document.querySelector('.scroll-content')
            let scrollItems = document.querySelectorAll('.scroll-item')
            // 判断滚动条是否滚动到底部
            if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
                this.activeStep = index
            }
            let total = scrollItems[index].offsetTop - scrollItems[0].offsetTop // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
            let distance = document.querySelector('.scroll-content').scrollTop + 10// 滚动条距离滚动区域顶部的距离
            // let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
            // 滚动动画实现, 使用setTimeout的递归实现平滑滚动，将距离细分为50小段，10ms滚动一次
            // 计算每一小段的距离
            let step = total / 50
            if (total > distance) {
                smoothDown(document.querySelector('.scroll-content'))
            } else {
                let newTotal = distance - total
                step = newTotal / 50
                smoothUp(document.querySelector('.scroll-content'))
            }
            // 参数element为滚动区域
            function smoothDown (element) {
                if (distance < total) {
                    distance += step
                    element.scrollTop = distance
                    setTimeout(smoothDown.bind(this, element), 10)
                } else {
                    element.scrollTop = total
                }
            }
            // 参数element为滚动区域
            function smoothUp (element) {
                if (distance > total) {
                    distance -= step
                    element.scrollTop = distance
                    setTimeout(smoothUp.bind(this, element), 10)
                } else {
                    element.scrollTop = total
                }
            }
        }
    }
}
</script>
<style lang="less" scoped>
.anchor-point {
    height: 100%;
    flex-basis: 100%;
    display: flex;
    overflow: hidden;

    .scroll-content {
        height: 100%;
        width: 90%;
        overflow: scroll;
        position: relative;
    }

    .operation-btn {
        width: 10%;
        height: 100%;
    }
}
</style>
